﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System.Web.Mvc;
using System.Linq.Expressions;
using System.ComponentModel.DataAnnotations;

namespace MethodWorx.CMS.UI.Tests
{
    public static class TestHelper
    {
        public static void AssertIsViewResult(ActionResult result, string name)
        {
            Assert.IsTrue(result is ViewResult, "ActionResult is not a view result");
            Assert.AreEqual(name, ((ViewResult)result).ViewName, "View names do not match");
        }

        public static void AssertDropDownContainsItems<TModel, T>(ActionResult result, Func<TModel, SelectList> modelSelectList, IEnumerable<T> items, Func<SelectListItem, T, bool> predicate)
            where TModel : class
        {
            Assert.IsTrue(result is ViewResult, "ActionResult is not a view result");
            TModel model = ((ViewResult)result).ViewData.Model as TModel;

            Assert.IsNotNull(model, "Model is null or incorrect type");

            var sl = modelSelectList.Invoke(model);

            Assert.IsNotNull(sl, "Select List is null");
            Assert.AreEqual(sl.Count(), items.Count(), "Select list contains different amount of items than source");

            foreach (T item in items)
            {
                if(sl.FirstOrDefault(sli => predicate(sli, item)) == null)
                    Assert.Fail("Select List Item Not Found");
            }
        }

        public static void AssertResultContainsError(ActionResult result, string errorMessage)
        {
            Assert.IsTrue(result is ViewResult, "ActionResult is not a view result");
            var ms = ((ViewResult)result).ViewData.ModelState;

            Assert.IsFalse(ms.IsValid, "Model Statis Is Valid");

            bool found = false;
            foreach (var m in ms.Values)
            {
                foreach (var e in m.Errors)
                {
                    if (e.ErrorMessage == errorMessage)
                    {
                        found = true;
                        break;
                    }
                }
            }

            Assert.IsTrue(found, "Model State Error {" + errorMessage + "} Not Found");
        }

        public static void AssertResultContainsError(ActionResult result, string field, string errorMessage)
        {
            Assert.IsTrue(result is ViewResult, "ActionResult is not a view result");
            var ms = ((ViewResult)result).ViewData.ModelState;

            Assert.IsFalse(ms.IsValid, "Model Statis Is Valid");

            bool found = false;
            foreach (var m in ms.Where(m => m.Key == field))
            {
                foreach (var e in m.Value.Errors)
                {
                    if (e.ErrorMessage == errorMessage)
                    {
                        found = true;
                        break;
                    }
                }
            }

            Assert.IsTrue(found, "Model State Error {" + errorMessage + "} for field " + field + " was Not Found");
        }

        public static TModel AssertResultContainsModel<TModel>(ActionResult result)
            where TModel: class
        {
            TModel model = ((ViewResult)result).ViewData.Model as TModel;
            Assert.IsNotNull(model, "Model is not required type: " + typeof(TModel));
            return model;
        }

        public static void AssertModelContainsRequiredValidationAttribute<TModel, TProperty>(Expression<Func<TModel, TProperty>> expr,string message)
        {
            Assert.IsTrue(((MemberExpression)expr.Body).Member.GetCustomAttributes(true).OfType<RequiredAttribute>().First().ErrorMessage == message);
        }
    }
}
